/* ================================================================
*   Copyright (C) 2020 All rights reserved.
*
*   文件名称：xio_util.h
*   创 建 者：xunmenglong
*   创建日期：2020年12月02日
*   描    述：跟文件IO的所有辅助函数
*
================================================================ */


#ifndef XIO_UTIL_H
#define XIO_UTIL_H

#include <stdio.h>
#include <fcntl.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <butil/logging.h>

using namespace std;

namespace xutil {

// 判断一个文件是否存在
inline bool is_file_exists(const char * file) {
    return (access(file, F_OK) != -1);
}

inline void x_mkdir(const char * dir) {
    string command = "mkdir -p ";
    command += dir;
    system(command.c_str());
}

inline void x_rmdir(const char * dir) {
    string command = "rm -rf ";
    command += dir;
    system(command.c_str());
}

// 获得一个文件的全部内容
inline string file_get_contents(string file) {
    ifstream fin;
    fin.open(file.c_str(), ios::in);
    stringstream buf;
    buf << fin.rdbuf();
    fin.close();

    return buf.str();
}

inline int x_msync(char * block, int len, int flag) {
    uint64_t block_addr = (uint64_t)block;
    // 生成页地址开始的地址
    uint64_t block_start_addr = block_addr >> 12 << 12;
    int new_len = (block_addr-block_start_addr) + len;
    return msync((void *)block_start_addr, new_len, flag);
}

inline char * x_mmap_file(const char * file) {
    int fd;
    struct stat sb;
    if((fd = open(file, O_RDWR)) < 0) {
        LOG(ERROR) << "open file: " << file << " fail";
        return NULL;
    }
    if((fstat(fd, &sb)) < 0) {
        LOG(ERROR) << "fstat file: " << file << " fail";
        return NULL;
    }
    char * block_ptr = (char *)mmap(NULL, sb.st_size,
            PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (block_ptr == MAP_FAILED) {
        LOG(ERROR) << "mmap file: " << file << " fail";
        return NULL;
    }
    close(fd);
    return block_ptr;
}

inline char * alloc_block(const char * file, int size) {
    if (is_file_exists(file)) {
        LOG(ERROR) << "cannot alloc exsits file: " << file;
        return NULL;
    }
    FILE * fp;
    fp = fopen(file, "w");
    int ret = ftruncate(fileno(fp), size);
    if (ret != 0) {
        LOG(ERROR) << "truncate " << file << errno << ": " << " fail";
        return NULL;
    }

    return x_mmap_file(file);
}

} // namespace xutil

#endif
